# Copyright (c) 2025, yuxinyong and contributors
# For license information, please see license.txt

import os
import io
from PIL import Image, ImageDraw, ImageFont
import frappe
from frappe.utils.file_manager import get_file, save_file
from frappe.core.doctype.file.utils import get_content_hash
from frappe.model.document import Document
from frappe.model.naming import make_autoname
from zelin_shoe_biz.utils import extract_last_number


class ShoeStyle(Document):
    # def autoname(self):s
    #     if not self.style:
    #         if self.customer_abbr:
    #             self.style = make_autoname(f"{self.customer_abbr}.####")
    #         else:
    #             self.style = make_autoname(self.series_name)
    #     self.name = self.style
    
    def before_save(self):
        self.sort_parts_by_sequence()
    
    def sort_parts_by_sequence(self):
        """按 sorting_sequence 重新排序子表"""
        if not self.shoe_parts:
            return
        
        # 按 sorting_sequence 排序
        sorted_parts = sorted(self.shoe_parts, key=lambda x: x.sorting_sequence or 0)
        
        # 清空原有子表并重新添加（这会重置 idx）
        self.shoe_parts = []
        for part in sorted_parts:
            self.append('shoe_parts', part)

    def validate(self):
        self.generate_annotated_image()

    def before_insert(self):
        self.last_number = extract_last_number(self.last)

    @frappe.whitelist()
    def new_component(self, component_type):
        fieldname = component_type.lower()
        if not self.last or self.get(fieldname): return

        component_doc = frappe.new_doc("Shoe Component")
        component_self.update({
            'last': self.last,
            'component_type': component_type
        })
        for row in self.shoe_parts:
            if row.component_type == component_type:
                component_self.append("shoe_parts", row)
        component_self.save()
        self.set(fieldname, component_self.name)
        return True

    @frappe.whitelist()
    def generate_annotated_image(self):
        frappe.log_error("TEST", "Annotation Error")
        should_regenerate = (self.image_link and 
            (not self.image_link_annotate or self.annotations_updated) and
            any(p.pic_position and p.pic_label and p.pic_color for p in self.shoe_parts)
        ) 
        if not should_regenerate:
            return

        # 1. Get the base image
        try:
            base_image_file = get_file(self.image_link)
            base_image = Image.open(io.BytesIO(base_image_file[1])).convert("RGBA")  # Fixed: Use BytesIO for bytes
            width, height = base_image.size
        except Exception as e:
            frappe.log_error( "Shoe Style Annotation Error", f"Could not open base image: {e}")
            return

        # 2. Prepare to draw
        draw = ImageDraw.Draw(base_image, "RGBA")

        # Calculate the full path to the font (assuming it's in a 'fonts' subfolder relative to this script)
        font_path = os.path.join(os.path.dirname(__file__), 'fonts', 'SplineSans-Regular.ttf')

        # Try to load the custom font, with fallback
        try:
            font = ImageFont.truetype(font_path, size=27)
        except IOError:
            font = ImageFont.load_default()
            frappe.log_error(f"Font not found at {font_path}, using default.", "Font Warning")

        # 3. Loop through annotations (shoe parts) and draw them
        for part in self.get("shoe_parts", []):
            if not (part.pic_position and part.pic_label):
                continue
            # Parse position (e.g., "50.12%, 30.45%")
            try:
                x_str, y_str = part.pic_position.split(',')
                x_pct = float(x_str.strip().replace('%', ''))
                y_pct = float(y_str.strip().replace('%', ''))
                # Convert percentage to pixel coordinates
                x = (x_pct / 100) * width
                y = (y_pct / 100) * height
            except (ValueError, IndexError):
                continue  # Skip if position is malformed
            label = part.pic_label
            color = part.pic_color or "white"
            # Calculate text bounding box to draw the background
            try:
                # For Pillow >= 10.0.0
                left, top, right, bottom = draw.textbbox((0, 0), label, font=font)
                text_width = right - left
                text_height = bottom - top
            except AttributeError:
                # For Pillow < 10.0.0
                text_width, text_height = draw.textsize(label, font=font)
            # Position background and text (centered on the coordinate)
            bg_x0 = x - (text_width / 2) - 5  # 5px padding
            bg_y0 = y - (text_height / 2) - 2  # 2px padding
            bg_x1 = bg_x0 + text_width + 10  # 10px total width padding
            bg_y1 = bg_y0 + text_height + 15  # 4px total height padding
            text_x = bg_x0 + 5
            text_y = bg_y0 + 2
            # Draw semi-transparent background and then the text
            draw.rectangle([bg_x0, bg_y0, bg_x1, bg_y1], fill=(0, 0, 0, 50))  # Black with ~70% opacity
            draw.text((text_x, text_y), label, font=font, fill=color)

        # 4. Save the new image to a file
        # Convert back to RGB for JPG saving (removes alpha channel)
        final_image = base_image.convert("RGB")
        # Create a unique filename
        new_filename = f"{self.style_name.replace(' ', '_')}_annotated.jpg"
        # Get JPEG bytes (Fixed: Use BytesIO instead of invalid tobytes)
        output_io = io.BytesIO()
        final_image.save(output_io, format='JPEG', quality=95)  # Quality optional, adjust as needed
        content = output_io.getvalue()

        # update the content if previous version exist        
        existing_file = frappe.db.get_value("File", {
            "attached_to_doctype": self.doctype,
            "attached_to_name": self.name,
            "attached_to_field": "image_link_annotate",
        })
        if existing_file:
            file_doc = frappe.get_doc("File", existing_file)
            file_doc.save_file(
                content=content,  # 新的内容
                decode=False,  # 如果是二进制内容设为 False
                overwrite=True  # 覆盖原文件
            )
            file_doc.content_hash = get_content_hash(content)
            file_doc.file_size = len(content)
            file_doc.save()
        else:
            # Save file and get Frappe File doc
            saved_file = save_file(
                fname=new_filename,
                content=content,
                dt=self.doctype,
                dn=self.name,
                df="image_link_annotate",
                folder="Home/Attachments",  # Or another desired folder
                is_private=0,  # Make it public
                decode=False  # We are passing bytes
            )

            # 5. Update the document and reset the flag
            # Use db_set to avoid triggering save hooks again (and causing a loop)
            self.image_link_annotate = saved_file.file_url
        self.annotations_updated = 0

        # Optional: Add success message for debugging (remove later)
        #frappe.msgprint("Annotated image generated and attached successfully.")

@frappe.whitelist()
def get_shoe_component_shoe_parts(shoe_component):
    meta = frappe.get_meta("Shoe Part Detail")
    columns = meta.get_valid_columns()
    default_fields = frappe.model.default_fields
    child_fields = frappe.model.child_table_fields
    # 仅需要业务字段
    fields = [c for c in columns if c not in default_fields and c not in child_fields]
    data = frappe.get_all("Shoe Part Detail", 
        filters = {
            "parent": shoe_component,
            "parenttype": "Shoe Component"
        },
        fields = fields
    )

    return data